/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// renderer.h - framework used by dynamic-link libraries
//


#ifndef __FRAMEWORK_RENDERER_H__
#define __FRAMEWORK_RENDERER_H__


/*
 ==============================================================================

 Renderer:

 The renderer is responsible for managing the screen, which can have multiple
 3D and 2D drawing done on it.

 All drawing is done to a 640x480 virtual screen resolution and will be
 automatically scaled to the real screen resolution and corrected for the
 screen aspect ratio.

 ==============================================================================
*/

// Virtual screen dimensions
#define SCREEN_WIDTH				640
#define SCREEN_HEIGHT				480

// Font support
#define FONTS_PER_SET				3
#define GLYPHS_PER_FONT				256

#define FONT_SMALL					0
#define FONT_MEDIUM					1
#define FONT_LARGE					2

// Material parms
#define MAX_MATERIAL_PARMS			8

#define MATERIALPARM_RED			0			// Used by "colored" materials
#define MATERIALPARM_GREEN			1			// Used by "colored" materials
#define MATERIALPARM_BLUE			2			// Used by "colored" materials
#define MATERIALPARM_ALPHA			3			// Used by "colored" materials
#define MATERIALPARM_TIMEOFFSET		4			// Render time offset
#define MATERIALPARM_DIVERSITY		5			// Random value for some effects
#define MATERIALPARM_MISC			6			// Miscellaneous value for some effects
#define MATERIALPARM_MODE			7			// For selecting which material stages to enable

// Render entity types
enum reType_t {
	RE_MODEL,
	RE_SPRITE,
	RE_BEAM
};

// Render light types
enum rlType_t {
	RL_POINT,
	RL_CUBIC,
	RL_PROJECTED,
	RL_DIRECTIONAL
};

// View types for per-view allow/suppress
enum viewType_t {
	VIEW_NONE						= 0,
	VIEW_MAIN						= BIT(0),
	VIEW_MIRROR						= BIT(1),
	VIEW_REMOTE						= BIT(2),
	VIEW_ALL						= BIT(3) - 1
};

// Horizontal adjustment for 2D drawing
enum horzAdjust_t {
	H_NONE,
	H_SCALE,
	H_ALIGN_LEFT,
	H_ALIGN_CENTER,
	H_ALIGN_RIGHT,
	H_STRETCH_LEFT,
	H_STRETCH_WIDTH,
	H_STRETCH_RIGHT
};

// Vertical adjustment for 2D drawing
enum vertAdjust_t {
	V_NONE,
	V_SCALE,
	V_ALIGN_TOP,
	V_ALIGN_CENTER,
	V_ALIGN_BOTTOM,
	V_STRETCH_TOP,
	V_STRETCH_HEIGHT,
	V_STRETCH_BOTTOM
};

enum glHardwareType_t {
	GLHW_GENERIC,
	GLHW_ATI,
	GLHW_NVIDIA
};

typedef struct model_t				model_t;
typedef struct material_t			material_t;
typedef struct skin_t				skin_t;
typedef struct scene_t				scene_t;

struct glyphInfo_t {
	int						image;				// Image index

	int						xAdjust;			// X adjustment
	int						yAdjust;			// Y adjustment

	int						width;				// Width of glyph
	int						height;				// Height of glyph

	float					s1;					// X offset in image where glyph starts
	float					t1;					// Y offset in image where glyph starts
	float					s2;					// X offset in image where glyph ends
	float					t2;					// Y offset in image where glyph ends

	material_t *			material;			// The material for the glyph
};

struct fontInfo_t {
	int						maxWidth;
	int						maxHeight;

	int						glyphImages;
	float					glyphScale;

	glyphInfo_t				glyphs[GLYPHS_PER_FONT];
};

struct fontSet_t {
	fontInfo_t				fontInfo[FONTS_PER_SET];
};

struct renderEntity_t {
	reType_t				type;

	int						entityNum;

	// Transformation matrix
	glqVec3					origin;
	glqMat3					axis;

	// Model specific
	model_t *				model;

	skin_t *				skin;				// NULL for no remappings

	int						frame;
	int						oldFrame;

	float					backLerp;			// 0.0 = current, 1.0 = old

	// Sprite specific
	bool					spriteOriented;
	float					spriteRadius;
	float					spriteRotation;

	// Beam specific
	glqVec3					beamEnd;
	float					beamWidth;
	float					beamLength;

	// Subview parameters for remote cameras
	bool					hasSubview;

	glqVec3					subviewOrigin;
	glqAngles				subviewAngles;

	float					subviewFovX;		// Only used for remote cameras
	float					subviewFovY;		// Only used for remote cameras

	// Entity attributes
	bool					depthHack;			// Hack the depth range to avoid poking into geometry (implies noShadows)

	int						allowInView;		// For per-view allow/suppress
	int						allowShadowInView;	// For per-view allow/suppress

	// Material
	material_t *			material;			// If not NULL, all surfaces will use this
	float					materialParms[MAX_MATERIAL_PARMS];

	material_t *			referenceMaterial;	// Used so models and flares can reference the proper light material

	int						soundEmitterHandle;	// Allows effects to be modified by sound amplitude
};

struct renderLight_t {
	rlType_t				type;

	int						lightNum;

	// Transformation matrix
	glqVec3					origin;
	glqVec3					center;				// Offset relative to origin (or direction to the light for directional lights)
	glqMat3					axis;

	// Bounding volume for point, cubic, and directional lights
	glqVec3					radius;

	// Frustum definition for projected lights
	float					xMin;
	float					xMax;

	float					yMin;
	float					yMax;

	float					zNear;
	float					zFar;

	// Shadowing parameters
	bool					noShadows;			// Used to override material settings

	float					shadowBias;
	float					shadowSlopeScaleBias;

	float					shadowSoftness;		// Scale for soft-shadow filtering

	// Fogging parameters
	float					fogDistance;
	float					fogHeight;

	// Volumetric lighting parameters
	float					volumeIntensity;	// If != 0.0, render volumetric light shafts

	bool					volumeShadows;
	bool					volumeInteractions;

	// Light attributes
	int						detailLevel;

	int						allowInView;		// For per-view allow/suppress

	// Material
	material_t *			material;			// If NULL, a default light material will be used
	float					materialParms[MAX_MATERIAL_PARMS];

	int						soundEmitterHandle;	// Allows effects to be modified by sound amplitude
};

struct renderParticle_t {
	int todo;
};

struct renderView_t {
	// Viewport
	int						x;
	int						y;
	int						width;
	int						height;

	// Horizontal adjustment
	horzAdjust_t			horzAdjust;
	float					horzPercent;

	// Vertical adjustment
	vertAdjust_t			vertAdjust;
	float					vertPercent;

	// Transformation matrix
	glqVec3					origin;
	glqMat3					axis;

	// Field of view
	float					fovX;
	float					fovY;
	float					fovScale;

	// Time in milliseconds for time dependent effects
	int						time;
};

struct glConfig_t {
	bool					initialized;

	glHardwareType_t		hardwareType;

	const char *			vendorString;
	const char *			rendererString;
	const char *			versionString;
	const char *			extensionsString;
	const char *			wglExtensionsString;

	const char *			shadingLanguageVersionString;

	bool					textureCompressionS3TCAvailable;
	bool					textureFilterAnisotropicAvailable;
	bool					swapControlAvailable;
	bool					swapControlTearAvailable;

	int						maxTextureSize;
	int						max3DTextureSize;
	int						maxCubeMapTextureSize;
	int						maxArrayTextureLayers;
	int						maxTextureUnits;
	int						maxTextureCoords;
	int						maxTextureImageUnits;
	int						maxVertexTextureImageUnits;
	int						maxCombinedTextureImageUnits;
	int						maxVertexAttribs;
	int						maxVaryingComponents;
	int						maxVertexUniformComponents;
	int						maxFragmentUniformComponents;
	int						maxColorAttachments;
	int						maxRenderbufferSize;
	float					maxTextureLODBias;
	float					maxTextureMaxAnisotropy;

	int						videoWidth;
	int						videoHeight;

	bool					isFullscreen;
	int						displayFrequency;

	int						colorBits;
	int						alphaBits;
	int						depthBits;
	int						stencilBits;

	int						multiSamples;
};

// Functions exported by the engine
struct glqRenderer_t {
	// Loads and prepares the given map for rendering
	void					(*LoadMap)(const char *name);

	// Loads and prepares post-process effects for the given map
	void					(*LoadPostProcess)(const char *name);

	// Loads and registers the given model
	model_t *				(*RegisterModel)(const char *name);

	// Loads and registers the given material
	material_t *			(*RegisterMaterial)(const char *name);
	material_t *			(*RegisterMaterialLight)(const char *name);
	material_t *			(*RegisterMaterialNoMip)(const char *name);

	// Returns the number of frames for the given model
	int						(*ModelFrames) (model_t *model);

	// Scenes can be allocated and freed as needed.
	// The client will allocate the primary scene for rendering the game view,
	// but other parts of the program can also allocate scenes for other uses,
	// like drawing 3D items in the HUD, or displaying models in a GUI.
	scene_t *				(*AllocScene)(bool primary);
	void					(*FreeScene)(scene_t *scene);

	// Entities, lights, and particles must be added to a given scene to
	// determine what will be drawn for a given view. Most update work is
	// deferred until it is determined that it is actually needed for a given
	// view.
	// Nothing is drawn until RenderScene is called.
	int						(*AddRenderEntity)(scene_t *scene, const renderEntity_t *renderEntity);
	void					(*UpdateRenderEntity)(scene_t *scene, int entityHandle, const renderEntity_t *renderEntity);
	void					(*RemoveRenderEntity)(scene_t *scene, int entityHandle);

	int						(*AddRenderLight)(scene_t *scene, const renderLight_t *renderLight);
	void					(*UpdateRenderLight)(scene_t *scene, int lightHandle, const renderLight_t *renderLight);
	void					(*RemoveRenderLight)(scene_t *scene, int lightHandle);

	int						(*AddRenderParticle)(scene_t *scene, const renderParticle_t *renderParticle);
	void					(*UpdateRenderParticle)(scene_t *scene, int particleHandle, const renderParticle_t *renderParticle);
	void					(*RemoveRenderParticle)(scene_t *scene, int particleHandle);

	// Generates lists of static shadows and interactions and precaches the
	// given lights.
	// If this isn't called after loading a map, all the world shadows and
	// interactions will be dynamically generated.
	void					(*PrecacheLights)(scene_t *scene, int numRenderLights, const renderLight_t *renderLights);

	// Rendering a scene may actually render multiple views for skies, mirrors,
	// portals, and remote cameras.
	// If primaryView is false, the world map will be ignored completely, which
	// is useful for rendering things like GUI models.
	void					(*RenderScene)(scene_t *scene, const renderView_t *renderView, bool primaryView);

	// Captures the render output to the given texture.
	// Returns false if the texture wasn't found or couldn't be dynamically
	// modified.
	bool					(*CaptureRenderToTexture)(const char *name);

	// Updates the given texture's image. The image data must be in RGBA
	// format.
	// Does not allocate memory, so the image pointer must remain valid for the
	// rest of the frame.
	// Returns false if the texture wasn't found or couldn't be dynamically
	// modified.
	bool					(*UpdateTextureImage)(const char *name, const byte *image, int width, int height);

	// 2D drawing just involves color and material parameters setting and axial
	// image subsections.
	// The horizontal / vertical adjustment parameters are used to control the
	// automatic coordinate scaling and aspect ratio correction on each axis
	// separately.
	void					(*SetColor)(const glqVec4 &rgba);
	void					(*SetColor1)(float l);
	void					(*SetColor2)(float l, float a);
	void					(*SetColor3)(float r, float g, float b);
	void					(*SetColor4)(float r, float g, float b, float a);

	void					(*SetParameter)(int index, float value);
	void					(*SetParameters)(const float parms[MAX_MATERIAL_PARMS]);

	void					(*DrawStretchPic)(float x, float y, float w, float h, float s1, float t1, float s2, float t2, horzAdjust_t horzAdjust, float horzPercent, vertAdjust_t vertAdjust, float vertPercent, material_t *material);
	void					(*DrawStretchPicEx)(float x, float y, float w, float h, float s1, float t1, float s2, float t2, float xShear, float yShear, float rotate, horzAdjust_t horzAdjust, float horzPercent, vertAdjust_t vertAdjust, float vertPercent, material_t *material);

	void					(*DrawChar)(float x, float y, float w, float h, int c, horzAdjust_t horzAdjust, float horzPercent, vertAdjust_t vertAdjust, float vertPercent, material_t *material);
	void					(*DrawString)(float x, float y, float w, float h, const char *string, const glqVec4 &color, bool forceColor, float xShadow, float yShadow, horzAdjust_t horzAdjust, float horzPercent, vertAdjust_t vertAdjust, float vertPercent, material_t *material);

	// The render output can be cropped down to a subset of the real screen.
	// To render to a texture, first set the crop size, then perform all
	// desired rendering, then capture to a texture.
	// The specified dimensions are in virtual SCREEN_WIDTH x SCREEN_HEIGHT
	// coordinates unless forceDimensions is true.
	// Users of the renderer will not know the actual pixel size of the area
	// they are rendering to.
	void					(*CropRenderSize)(int width, int height, bool forceDimensions);
	void					(*UnCropRenderSize)(void);

	// Debug visualization functions
	void					(*DebugAxis)(const glqVec3 &origin, const glqMat3 &axis, float size, bool depthTest, int allowInView);
	void					(*DebugLine)(const glqVec4 &color, const glqVec3 &start, const glqVec3 &end, bool depthTest, int allowInView);
	void					(*DebugArrow)(const glqVec4 &color, const glqVec3 &start, const glqVec3 &end, float size, bool depthTest, int allowInView);
	void					(*DebugBounds)(const glqVec4 &color, const glqBounds &bounds, bool depthTest, int allowInView);
	void					(*DebugSphere)(const glqVec4 &color, const glqSphere &sphere, bool depthTest, int allowInView);
	void					(*DebugBox)(const glqVec4 &color, const glqVec3 &origin, const glqMat3 &axis, const glqBounds &bounds, bool depthTest, int allowInView);
	void					(*DebugCone)(const glqVec4 &color, const glqVec3 &apex, const glqVec3 &direction, float apexRadius, float baseRadius, bool depthTest, int allowInView);
	void					(*DebugCircle)(const glqVec4 &color, const glqVec3 &origin, const glqVec3 &direction, float radius, int steps, bool depthTest, int allowInView);
	void					(*DebugFrustum)(const glqVec4 &color, const glqVec3 &origin, const glqMat3 &axis, float xMin, float xMax, float yMin, float yMax, float zNear, float zFar, bool depthTest, int allowInView);
	void					(*DebugPolygon)(const glqVec4 &color, int numPoints, const glqVec3 *points, bool fill, bool depthTest, int allowInView);
	void					(*DebugText)(const glqVec4 &color, bool forceColor, const glqVec3 &origin, float cw, float ch, const char *text, bool depthTest, int allowInView);

	// Returns information about the OpenGL subsystem
	glConfig_t				(*GetGLConfig)();
};


#endif	// __FRAMEWORK_RENDERER_H__